from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from rest_framework import status
from .permissions import PermissionChecker
from .models import AdminUser
import json


class AdminPermissionMiddleware(MiddlewareMixin):
    """
    管理员权限检查中间件
    """
    
    # 需要管理员权限的URL前缀
    ADMIN_URL_PREFIXES = [
        '/api/admin/',
        '/admin-api/',
    ]
    
    # 不需要权限检查的URL
    EXEMPT_URLS = [
        '/api/admin/login/',
        '/api/admin/logout/',
        '/api/admin/profile/',
    ]
    
    def process_request(self, request):
        """
        处理请求前的权限检查
        """
        # 检查是否为管理员API请求
        if not self._is_admin_request(request):
            return None
        
        # 检查是否为免检URL
        if self._is_exempt_url(request):
            return None
        
        # 检查用户认证
        if not request.user or not request.user.is_authenticated:
            return self._permission_denied_response("用户未认证")
        
        # 检查是否为管理员
        try:
            admin_user = AdminUser.objects.get(user=request.user)
            if not admin_user.is_active:
                return self._permission_denied_response("管理员账户已被禁用")
        except AdminUser.DoesNotExist:
            return self._permission_denied_response("用户不是管理员")
        
        # 将管理员用户信息添加到请求中
        request.admin_user = admin_user
        
        return None
    
    def _is_admin_request(self, request):
        """
        检查是否为管理员API请求
        """
        path = request.path
        return any(path.startswith(prefix) for prefix in self.ADMIN_URL_PREFIXES)
    
    def _is_exempt_url(self, request):
        """
        检查是否为免检URL
        """
        path = request.path
        return any(path.startswith(url) for url in self.EXEMPT_URLS)
    
    def _permission_denied_response(self, message):
        """
        返回权限拒绝响应
        """
        return JsonResponse({
            'error': message,
            'code': 'PERMISSION_DENIED'
        }, status=status.HTTP_403_FORBIDDEN)


class AuditLogMiddleware(MiddlewareMixin):
    """
    审计日志中间件
    """
    
    def process_request(self, request):
        """
        记录请求开始时间
        """
        import time
        request._audit_start_time = time.time()
        return None
    
    def process_response(self, request, response):
        """
        记录审计日志
        """
        # 只记录管理员API的审计日志
        if not self._should_audit(request):
            return response
        
        try:
            self._create_audit_log(request, response)
        except Exception as e:
            # 审计日志失败不应该影响正常请求
            print(f"审计日志记录失败: {e}")
        
        return response
    
    def _should_audit(self, request):
        """
        检查是否需要记录审计日志
        """
        path = request.path
        admin_prefixes = ['/api/admin/', '/admin-api/']
        return any(path.startswith(prefix) for prefix in admin_prefixes)
    
    def _create_audit_log(self, request, response):
        """
        创建审计日志
        """
        from .models import AuditLog
        import time
        
        # 计算请求处理时间
        start_time = getattr(request, '_audit_start_time', time.time())
        duration = time.time() - start_time
        
        # 获取请求数据
        request_data = self._get_request_data(request)
        
        # 获取用户信息
        user = request.user if request.user.is_authenticated else None
        admin_user = getattr(request, 'admin_user', None)
        
        # 创建审计日志
        AuditLog.objects.create(
            user=user,
            admin_user=admin_user,
            action=f"{request.method} {request.path}",
            resource=self._extract_resource(request.path),
            ip_address=self._get_client_ip(request),
            user_agent=request.META.get('HTTP_USER_AGENT', ''),
            request_data=request_data,
            response_status=response.status_code,
            duration=duration,
            success=200 <= response.status_code < 400
        )
    
    def _get_request_data(self, request):
        """
        获取请求数据
        """
        try:
            if request.content_type == 'application/json':
                return json.loads(request.body.decode('utf-8'))
            elif request.method in ['POST', 'PUT', 'PATCH']:
                return dict(request.POST)
            else:
                return dict(request.GET)
        except Exception:
            return {}
    
    def _extract_resource(self, path):
        """
        从路径中提取资源名称
        """
        parts = path.strip('/').split('/')
        if len(parts) >= 3 and parts[0] == 'api' and parts[1] == 'admin':
            return parts[2]
        return 'unknown'
    
    def _get_client_ip(self, request):
        """
        获取客户端IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip


class SecurityHeadersMiddleware(MiddlewareMixin):
    """
    安全头中间件
    """
    
    def process_response(self, request, response):
        """
        添加安全头
        """
        # 只对管理员API添加安全头
        if self._is_admin_api(request):
            # 防止点击劫持
            response['X-Frame-Options'] = 'DENY'
            
            # 防止MIME类型嗅探
            response['X-Content-Type-Options'] = 'nosniff'
            
            # XSS保护
            response['X-XSS-Protection'] = '1; mode=block'
            
            # 强制HTTPS
            response['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
            
            # 内容安全策略
            response['Content-Security-Policy'] = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
            
            # 引用策略
            response['Referrer-Policy'] = 'strict-origin-when-cross-origin'
        
        return response
    
    def _is_admin_api(self, request):
        """
        检查是否为管理员API
        """
        path = request.path
        admin_prefixes = ['/api/admin/', '/admin-api/']
        return any(path.startswith(prefix) for prefix in admin_prefixes)


class RateLimitMiddleware(MiddlewareMixin):
    """
    速率限制中间件
    """
    
    def __init__(self, get_response):
        super().__init__(get_response)
        self.cache = {}
        self.cleanup_interval = 300  # 5分钟清理一次缓存
        self.last_cleanup = 0
    
    def process_request(self, request):
        """
        检查速率限制
        """
        import time
        
        # 只对管理员API进行速率限制
        if not self._is_admin_api(request):
            return None
        
        # 清理过期缓存
        current_time = time.time()
        if current_time - self.last_cleanup > self.cleanup_interval:
            self._cleanup_cache(current_time)
            self.last_cleanup = current_time
        
        # 获取客户端标识
        client_id = self._get_client_id(request)
        
        # 检查速率限制
        if self._is_rate_limited(client_id, current_time):
            return JsonResponse({
                'error': '请求过于频繁，请稍后再试',
                'code': 'RATE_LIMITED'
            }, status=status.HTTP_429_TOO_MANY_REQUESTS)
        
        return None
    
    def _is_admin_api(self, request):
        """
        检查是否为管理员API
        """
        path = request.path
        admin_prefixes = ['/api/admin/', '/admin-api/']
        return any(path.startswith(prefix) for prefix in admin_prefixes)
    
    def _get_client_id(self, request):
        """
        获取客户端标识
        """
        # 优先使用用户ID，其次使用IP地址
        if request.user and request.user.is_authenticated:
            return f"user_{request.user.id}"
        else:
            ip = self._get_client_ip(request)
            return f"ip_{ip}"
    
    def _get_client_ip(self, request):
        """
        获取客户端IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def _is_rate_limited(self, client_id, current_time):
        """
        检查是否超过速率限制
        """
        # 每分钟最多60次请求
        window_size = 60  # 1分钟
        max_requests = 60
        
        if client_id not in self.cache:
            self.cache[client_id] = []
        
        # 清理过期请求
        requests = self.cache[client_id]
        requests[:] = [req_time for req_time in requests if current_time - req_time < window_size]
        
        # 检查是否超过限制
        if len(requests) >= max_requests:
            return True
        
        # 记录当前请求
        requests.append(current_time)
        return False
    
    def _cleanup_cache(self, current_time):
        """
        清理过期缓存
        """
        window_size = 60
        for client_id in list(self.cache.keys()):
            requests = self.cache[client_id]
            requests[:] = [req_time for req_time in requests if current_time - req_time < window_size]
            if not requests:
                del self.cache[client_id]